/**
 * Copyright 2019 吉鼎科技.

 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.easyplatform.web.controller.admin;

import cn.easyplatform.lang.Strings;
import cn.easyplatform.messages.request.SimpleRequestMessage;
import cn.easyplatform.messages.request.admin.ServiceRequestMessage;
import cn.easyplatform.messages.vos.admin.CustomVo;
import cn.easyplatform.messages.vos.admin.ModelVo;
import cn.easyplatform.messages.vos.admin.ProjectVo;
import cn.easyplatform.messages.vos.admin.ServiceVo;
import cn.easyplatform.spi.service.AdminService;
import cn.easyplatform.type.IResponseMessage;
import cn.easyplatform.type.ModeType;
import cn.easyplatform.type.ServiceType;
import cn.easyplatform.type.StateType;
import cn.easyplatform.web.WebApps;
import cn.easyplatform.web.dialog.MessageBox;
import cn.easyplatform.web.service.ServiceLocator;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.zkoss.util.resource.Labels;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Executions;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zk.ui.select.SelectorComposer;
import org.zkoss.zk.ui.select.annotation.Listen;
import org.zkoss.zk.ui.select.annotation.Wire;
import org.zkoss.zkmax.zul.Filedownload;
import org.zkoss.zkmax.zul.Scrollview;
import org.zkoss.zul.*;
import org.zkoss.zul.theme.Themes;

import java.util.*;


/**
 * @author <a href="mailto:davidchen@epclouds.com">littleDog</a> <br/>
 * @since 2.0.0 <br/>
 */
public class ProjectController extends SelectorComposer<Component> {

    /**
     *
     */
    private static final long serialVersionUID = 1L;

    private final static int PROPERTY_SEP_INDEX = 12;

    private ProjectVo pv;

    @Wire("textbox#name")
    private Textbox name;

    @Wire("textbox#desp")
    private Textbox desp;

    @Wire("textbox#appContext")
    private Textbox appContext;

    @Wire("combobox#bizDb")
    private Combobox bizDb;

    @Wire("combobox#identityDb")
    private Combobox identityDb;

    @Wire("textbox#languages")
    private Textbox languages;

    @Wire("button#themesBtn")
    private Button themesBtn;

    @Wire("radiogroup#serviceModel")
    private Radiogroup serviceModel;

    @Wire("button#serviceOp")
    private Button serviceOp;

    @Wire("listbox#projectProperties")
    private Listbox projectProperties;

    @Wire("listcell#startTime")
    private Listcell startTime;

    @Wire("scrollview#themes")
    private Scrollview themes;

    @Wire("popup#themesPop")
    private Popup pop;

    private Vlayout currentLayout;

    private List<String> ids;
    private List<String> names;

    @Override
    public void doAfterCompose(Component comp) throws Exception {
        super.doAfterCompose(comp);
        AdminService as = ServiceLocator.lookup(AdminService.class);
        IResponseMessage<?> resp = as.getService(new ServiceRequestMessage(new ServiceVo("", "", ServiceType.PROJECT, 0)));
        if (resp.isSuccess()) {
            pv = (ProjectVo) resp.getBody();
            if (pv.getState() == StateType.START) {
                serviceOp.setLabel(Labels
                        .getLabel("admin.service.state.blocked"));
                serviceOp.setIconSclass("z-icon-cog z-icon-spin");
                serviceOp.setTooltiptext(Labels
                        .getLabel("admin.service.pause.tooltip"));
                Date date = (Date) pv.getRuntimeInfo().get("service.start.time");
                if (date != null)
                    startTime.setLabel(Labels.getLabel("service.start.time") + " : " + DateFormatUtils.format(date,
                            "yyyy-MM-dd hh:mm:ss"));
            } else {
                serviceOp.setLabel(Labels
                        .getLabel("admin.service.state.paused"));
                serviceOp.setIconSclass("z-icon-lock");
                serviceOp.setTooltiptext(Labels
                        .getLabel("admin.service.resume.tooltip"));
            }
            resp = as.getServices(new SimpleRequestMessage(ServiceType.DATASOURCE));
            if (!resp.isSuccess()) {
                MessageBox.showMessage(resp);
                comp.detach();
                return;
            }
            List<ServiceVo> list = (List<ServiceVo>) resp.getBody();
            for (ServiceVo s : list) {
                if (s.getState() == StateType.START) {
                    Comboitem item = new Comboitem();
                    item.setLabel(s.getId());
                    item.setDescription(s.getName());
                    item.setValue(s);
                    bizDb.appendChild(item);
                    identityDb.appendChild((Comboitem) item.clone());
                }
            }
            List<String> lists = new ArrayList<>();
            for (String themeName : Themes.getThemes()) {
                if (themeName.endsWith("_c") || themeName.equals("sapphire") || themeName.equals("breeze") || themeName.equals("silvertail"))
                    lists.add(themeName);
            }
            String[] id = new String[]{"Aquamarine", "atrovirens_c", "Aurora", "Blueberry", "Emerald", "Iceblue", "Lavender",
                    "Marigold", "Montana", "Mysterious", "Office", "Olive", "Poppy", "Ruby", "Space"};
            String[] nameList = new String[]{Labels.getLabel("theme.name.color.aquamarine"), Labels.getLabel("theme.name.color.atrovirens_c"),
                    Labels.getLabel("theme.name.color.aurora"), Labels.getLabel("theme.name.color.blueberry"), Labels.getLabel("theme.name.color.emerald"),
                    Labels.getLabel("theme.name.color.iceblue"), Labels.getLabel("theme.name.color.lavender"), Labels.getLabel("theme.name.color.marigold"),
                    Labels.getLabel("theme.name.color.montana"), Labels.getLabel("theme.name.color.mysterious"), Labels.getLabel("theme.name.color.office"),
                    Labels.getLabel("theme.name.color.olive"), Labels.getLabel("theme.name.color.poppy"), Labels.getLabel("theme.name.color.ruby"),
                    Labels.getLabel("theme.name.color.space")};
            ids = Arrays.asList(id);
            names = Arrays.asList(nameList);
            Collections.sort(lists);
            if (lists != null || lists.size() > 0) {
                //每一行最外层控件
                Div contentDiv = new Div();
                contentDiv.setHflex("1");
                contentDiv.setStyle("display: flex;flex-direction: row;flex-wrap: wrap;min-width:164px;justify-content: flex-start;");
                themes.appendChild(contentDiv);
                for (int index = 0; index < lists.size(); index++) {
                    String displayName = Themes.getDisplayName(lists.get(index));
                    Integer showIndex = ids.indexOf(displayName.split(" ")[0]);
                    if (showIndex >= 0) {
                        new ProjectController.ThemesCell(lists.get(index), displayName.split(" ")[0], contentDiv);
                    }
                }
            }
            setValues();
        } else {
            MessageBox.showMessage(resp);
            comp.detach();
        }
    }

    private void setValues() {
        ((Listcell) projectProperties.getItemAtIndex(1).getLastChild()).setLabel(pv.getId());
        ((Listcell) projectProperties.getItemAtIndex(2).getLastChild()).setLabel(pv.getEntityTableName());
        name.setValue(pv.getName());
        desp.setValue(pv.getDesp());
        appContext.setValue(pv.getAppContext());
        for (Comboitem item : bizDb.getItems()) {
            if (item.getLabel().equals(pv.getBizDb())) {
                bizDb.setSelectedItem(item);
                break;
            }
        }
        for (Comboitem item : identityDb.getItems()) {
            if (Strings.isBlank(pv.getIdentityDb())) {
                if (item.getLabel().equals(pv.getBizDb())) {
                    identityDb.setSelectedItem(item);
                    break;
                }
            } else {
                if (item.getLabel().equals(pv.getIdentityDb())) {
                    identityDb.setSelectedItem(item);
                    break;
                }
            }
        }
        languages.setValue(pv.getLanguages());
        String theme = pv.getTheme();
        if (Strings.isBlank(theme))
            theme = Themes.getCurrentTheme();
        themesBtn.setLabel(theme);
        if (pv.getMode() == ModeType.ONLINE)
            serviceModel.setSelectedIndex(0);
        else if (pv.getMode() == ModeType.DEVELOP)
            serviceModel.setSelectedIndex(1);
        else
            serviceModel.setSelectedIndex(2);
        if (projectProperties.getItemCount() > PROPERTY_SEP_INDEX) {
            List<Listitem> items = new ArrayList<Listitem>();
            for (int i = PROPERTY_SEP_INDEX; i < projectProperties.getItemCount(); i++)
                items.add(projectProperties.getItemAtIndex(i));
            for (Listitem item : items)
                item.detach();
        }
        Map<String, String> map = new TreeMap<>(pv.getProperties());
        for (Map.Entry<String, String> entry : map.entrySet()) {
            if (!entry.getKey().equals("config") && !entry.getKey().equals("services") && !entry.getKey().equals("commands")) {
                Listitem item = new Listitem();
                String label = Labels.getLabel("admin." + entry.getKey());
                Listcell name = new Listcell(label == null ? entry.getKey() : label);
                name.setValue(entry.getKey());
                item.appendChild(name);
                Listcell cell = new Listcell();
                Textbox tb = new Textbox(entry.getValue());
                tb.setHflex("1");
                tb.setInplace(true);
                cell.appendChild(tb);
                item.appendChild(cell);
                projectProperties.appendChild(item);
            }
        }
        String config = pv.getProperties().get("config");
        if (!Strings.isBlank(config)) {
            final String configValue = config;
            Listitem item = new Listitem();
            item.appendChild(new Listcell(Labels.getLabel("admin.config")));
            Listcell cell = new Listcell(config.trim());
            cell.addEventListener(Events.ON_CLICK,
                    evt -> new EditorDialog(value -> {
                        pv.getProperties().remove(
                                "importConfig");
                        pv.getProperties().put("config", value);
                    }).showDialog(evt.getPage(), "properties",
                            configValue));
            item.appendChild(cell);
            projectProperties.appendChild(item);
        }

    }

    @Listen("onClick=#themesBtn")
    public void onSelectTheme() {
        pop.open(themesBtn, "after_start");
    }

    private class ThemesCell implements EventListener<Event> {

        public ThemesCell(String themeId, String themeName, Component parentLayout) {
            if (Strings.isBlank(themeName)) {
                Div div = new Div();
                div.setHflex("1");
                parentLayout.appendChild(div);
            } else {
                Integer index = ids.indexOf(themeName);
                Vlayout contentLayout = new Vlayout();
                contentLayout.setSpacing("0");
                contentLayout.setHeight("200px");
                contentLayout.setWidth("164px");
                contentLayout.setStyle("text-align: center;");//;border:#195B40 solid 2px;
                contentLayout.setSclass("ui-div-normal");
                contentLayout.addEventListener(Events.ON_CLICK, this);
                contentLayout.setId(themeId);
                parentLayout.appendChild(contentLayout);

                Div oneDiv = new Div();
                oneDiv.setHeight("15px");
                contentLayout.appendChild(oneDiv);

                Image contentImage = new Image();
                contentImage.setSrc("~./img/theme/" + themeName + ".png");
                contentImage.setHeight("137px");
                contentImage.setWidth("137px");
                contentLayout.appendChild(contentImage);

                Div secondDiv = new Div();
                secondDiv.setHeight("8px");
                contentLayout.appendChild(secondDiv);

                Label contentLabel = new Label();
                contentLabel.setValue(names.get(index));
                contentLabel.setStyle("font-size:12px;border-radius: 14px;padding: 2px 8px;");
                contentLayout.appendChild(contentLabel);

                Div lastDiv = new Div();
                lastDiv.setHeight("8px");
                contentLayout.appendChild(lastDiv);
                String theme = Themes.getCurrentTheme();
                if (theme.equals(themeId)) {
                    currentLayout = contentLayout;
                    currentLayout.setSclass("ui-div-selected");
                }
            }
        }

        @Override
        public void onEvent(Event event) throws Exception {
            if (event.getTarget() instanceof Vlayout) {
                if (currentLayout != event.getTarget()) {
                    ((Vlayout) event.getTarget()).setSclass("ui-div-selected");
                    currentLayout.setSclass("ui-div-normal");
                    currentLayout = (Vlayout) event.getTarget();
                }
            }
        }
    }

    @Listen("onClick=#submit")
    public void submitTheme() {
        String theme = currentLayout.getId();
        pop.close();
        themesBtn.setLabel(theme);
    }

    @Listen("onClick=#addProperty")
    public void onAdd() {
        Listitem item = new Listitem();
        Textbox tb = new Textbox("key");
        tb.setHflex("1");
        Listcell cell = new Listcell();
        cell.appendChild(tb);
        cell.setParent(item);

        cell = new Listcell();
        tb = new Textbox("value");
        tb.setHflex("1");
        cell.appendChild(tb);
        item.appendChild(cell);
        projectProperties.insertBefore(item, projectProperties.getItemAtIndex(PROPERTY_SEP_INDEX));
    }

    @Listen("onClick=#removeProperty")
    public void onRemove() {
        if (projectProperties.getSelectedIndex() > PROPERTY_SEP_INDEX) {
            final Listitem li = projectProperties.getSelectedItem();
            String name = null;
            if (li.getFirstChild().getFirstChild() != null && li.getFirstChild().getFirstChild() instanceof Textbox) {
                name = ((Textbox) li.getFirstChild().getFirstChild()).getValue();
                pv.getProperties().remove(name);
            } else {
                Listcell kc = (Listcell) li.getFirstChild();
                name = kc.getValue();
                if (Strings.isBlank(name))
                    name = kc.getLabel();
                pv.getProperties().remove(name);
            }
            final String key = name;
            Messagebox.show(Labels.getLabel("admin.service.op.confirm",
                    new Object[]{Labels.getLabel("admin.project.property.remove")
                            + name}), Labels.getLabel("admin.service.op.title"),
                    Messagebox.CANCEL | Messagebox.OK, Messagebox.QUESTION,
                    evt -> {
                        if (evt.getName().equals(Messagebox.ON_OK)) {
                            pv.getProperties().remove(key);
                            li.detach();
                        }
                    });
        }
    }

    @Listen("onClick=#load")
    public void onLoad() {
        AdminService as = ServiceLocator.lookup(AdminService.class);
        IResponseMessage<?> resp = as.getModel(new SimpleRequestMessage(new ModelVo(pv.getId())));
        if (!resp.isSuccess())
            MessageBox.showMessage(resp);
        else {
            this.pv = (ProjectVo) resp.getBody();
            setValues();
        }
    }

    @Listen("onClick=#save")
    public void onSave() {
        pv.setName(name.getValue());
        pv.setDesp(desp.getValue());
        pv.setAppContext(appContext.getValue());
        pv.setBizDb(bizDb.getSelectedItem().getLabel());
        String val = identityDb.getSelectedItem().getLabel();
        if (val.equals(pv.getBizDb()))
            pv.setIdentityDb("");
        else
            pv.setIdentityDb(val);
        pv.setLanguages(languages.getValue());
        if (serviceModel.getSelectedIndex() == 0)
            pv.setMode(ModeType.ONLINE);
        else if (serviceModel.getSelectedIndex() == 1)
            pv.setMode(ModeType.DEVELOP);
        else
            pv.setMode(ModeType.TEST);
        /*if (themes.getSelectedIndex() > -1) {
            String theme = themes.getSelectedItem().getValue();
            pv.setTheme(theme);
        }*/
        String theme = themesBtn.getLabel();
        pv.setTheme(theme);
        List<Listitem> items = projectProperties.getItems();
        if (items.size() > PROPERTY_SEP_INDEX) {// 自定义属性开始
            for (int i = PROPERTY_SEP_INDEX; i < items.size(); i++) {
                Listitem li = items.get(i);
                if (li.getFirstChild().getFirstChild() != null && li.getFirstChild().getFirstChild() instanceof Textbox) {
                    //新增加的属性
                    String name = ((Textbox) li.getFirstChild().getFirstChild()).getValue();
                    String value = ((Textbox) li.getLastChild().getFirstChild()).getValue();
                    if (!Strings.isBlank(name) && !Strings.isBlank(value)) {
                        pv.getProperties().put(name, value);
                    }
                } else {
                    Listcell kc = (Listcell) li.getFirstChild();
                    String name = kc.getValue();
                    if (Strings.isBlank(name))
                        name = kc.getLabel();
                    Listcell c = (Listcell) li.getLastChild();
                    if (c.getFirstChild() != null) {
                        Textbox tb = (Textbox) c.getFirstChild();
                        //空值去掉
                        if (Strings.isBlank(tb.getValue()))
                            pv.getProperties().remove(name);
                        else
                            pv.getProperties().put(name, tb.getValue());
                    }
                }
            }
        }
        AdminService as = ServiceLocator.lookup(AdminService.class);
        IResponseMessage<?> resp = as
                .saveProject(new SimpleRequestMessage(pv));
        if (!resp.isSuccess())
            MessageBox.showMessage(resp);
        else {
            setValues();
        }
    }

    //@Listen("onClick=#reset")
    public void onResetConfig(Event event) {
        AdminService as = ServiceLocator.lookup(AdminService.class);
        IResponseMessage<?> resp = as.resetCache(new SimpleRequestMessage("System"));
        if (!resp.isSuccess())
            MessageBox.showMessage(resp);
        else
            MessageBox.showInfo(Labels.getLabel("admin.service.op.title"), Labels.getLabel("common.success", new Object[]{((Button) event.getTarget()).getLabel()}));
    }

    @Listen("onClick=#serviceOp")
    public void onServiceOp() {
        String msg = null;
        if (pv.getState() == StateType.START)
            msg = Labels.getLabel("admin.service.pause");
        else
            msg = Labels.getLabel("admin.service.resume");
        Messagebox.show(Labels.getLabel("admin.service.op.confirm",
                new Object[]{msg}), Labels
                        .getLabel("admin.service.op.title"), Messagebox.CANCEL
                        | Messagebox.OK, Messagebox.QUESTION,
                new EventListener<Event>() {

                    @Override
                    public void onEvent(Event evt) throws Exception {
                        if (evt.getName().equals(Messagebox.ON_OK)) {
                            int state = StateType.START;
                            if (pv.getState() == StateType.START) {
                                serviceOp.setLabel(Labels
                                        .getLabel("admin.service.state.paused"));
                                serviceOp.setIconSclass("z-icon-lock");
                                serviceOp.setTooltiptext(Labels
                                        .getLabel("admin.service.resume.tooltip"));
                                state = StateType.PAUSE;
                            } else {
                                serviceOp.setLabel(Labels
                                        .getLabel("admin.service.state.blocked"));
                                serviceOp.setIconSclass("z-icon-cog z-icon-spin");
                                serviceOp.setTooltiptext(Labels
                                        .getLabel("admin.service.pause.tooltip"));
                            }
                            pv.setState(state);
                            AdminService as = ServiceLocator
                                    .lookup(AdminService.class);
                            as.setServiceState(new ServiceRequestMessage(new ServiceVo(pv.getId(), ServiceType.PROJECT, pv.getState())));
                        }
                    }
                });
    }

    @Listen("onClick=#downloadPK")
    public void onDownloadPK() {
        Filedownload.save(Base64.getEncoder().encodeToString(WebApps.me().getPublicKey().getEncoded()), "text/plain", "public-key.txt");
    }

    @Listen("onClick=#services")
    public void onConfigServices() {
        AdminService as = ServiceLocator.lookup(AdminService.class);
        IResponseMessage<?> resp = as.getConfig(new SimpleRequestMessage("services"));
        if (resp.isSuccess())
            new ClassDialog((CustomVo) resp.getBody()).showDialog(languages.getPage());
        else
            MessageBox.showMessage(resp);
    }

    @Listen("onClick=#commands")
    public void onConfigCommands() {
        AdminService as = ServiceLocator.lookup(AdminService.class);
        IResponseMessage<?> resp = as.getConfig(new SimpleRequestMessage("commands"));
        if (resp.isSuccess())
            new ClassDialog((CustomVo) resp.getBody()).showDialog(languages.getPage());
        else
            MessageBox.showMessage(resp);
    }
}
